package com.igoal.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.velocity.VelocityEngineUtils;

import com.igoal.dto.UserDTO;

@Service("mailService")
public class MailServiceImpl implements MailService {

	private static Log logger = LogFactory.getLog(MailServiceImpl.class);

	public static final String DEFAULT_FROM = "iGoal<igoal.developers@gmail.com>";
	public static final String DEFAULT_NOREPLY_FROM = "iGoal<no-reply@igoal.vn>";
	private static final String WELCOME_SUBJECT = "Welcome to iGoal.vn";
	private static final String WELCOME_TEMPLATE = "/email/templates/welcome.vm";
	private static final String FORGOT_PASSWORD_SUBJECT = "New iGoal password";
	private static final String FORGOT_PASSWORD_TEMPLATE = "/email/templates/forgotPassword.vm";
	private static final String ACTIVATION_SUBJECT = "iGoal Activation Code";
	private static final String ACTIVATION_TEMPLATE = "/email/templates/activation.vm";
	private static final String FRIEND_REQUEST_SUBJECT = "iGoal - Friend Request";
	private static final String FRIEND_REQUEST_TEMPLATE = "/email/templates/friendRequestEmail.vm";
	private static final String FRIEND_ACCEPT_SUBJECT = "iGoal - Friend Accept";
	private static final String FRIEND_ACCEPT_TEMPLATE = "/email/templates/friendAcceptEmail.vm";
	private static final String XMAS_WISH_TITLE = " vua gui ban mot loi chuc Giang Sinh that dac biet!";
	private static final String XMAS_WISH_TEMPLATE = "/email/templates/xmas.vm";
	private static final String XMAS_WISH_REPORT_TITLE = "iGoal - XMAS";
	private static final String XMAS_WISH_REPORT_TEMPLATE = "/email/templates/xmasReport.vm";

	private static final int THREAD_POOL_SIZE = 10;
	
	private static final List<SendEmailTask> queue = Collections
			.synchronizedList(new ArrayList<SendEmailTask>());
	
	static {
		// notification mail thread
		Thread sendingThread = new Thread(new Runnable() {
			ExecutorService mailThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

			public void run() {
				List<SendEmailTask> sendingList = new ArrayList<SendEmailTask>();
				while (true) {
					synchronized (queue) {
						sendingList.clear();
						sendingList.addAll(queue);
						queue.clear();
					}

					if (sendingList.size() > 0) {
						try {
							mailThreadPool.invokeAll(sendingList);
						} catch (InterruptedException e) {
							logger.error("", e);
						}
					}

					try {
						Thread.sleep(30000);
					} catch (InterruptedException e) {
						logger.error("", e);
					}
				}
			}
		});
		sendingThread.start();
	}

	@Autowired
	@Qualifier("mailSender")
	private JavaMailSenderImpl mailSender;
	
	@Autowired
	private VelocityEngine velocityEngine;

	public void setMailEngine(JavaMailSenderImpl mailSender) {
		this.mailSender = mailSender;
	}

	public void setVelocityEngine(VelocityEngine velocityEngine) {
		this.velocityEngine = velocityEngine;
	}

	public void sendWelcome(UserDTO user) {
		logger.debug("Send welcome email to " + user.getUsername());
		Map<String, String> model = new HashMap<String, String>();
		model.put("username", user.getUsername());
		sendMail(user.getEmail(), WELCOME_SUBJECT, WELCOME_TEMPLATE, model);
	}

	public void sendPassword(UserDTO user, String password) {
		logger.debug(user.getUsername() + " requested a new password");
		Map<String, String> model = new HashMap<String, String>();
		model.put("name", user.getUsername());
		model.put("password", password);
		sendMail(user.getEmail(), FORGOT_PASSWORD_SUBJECT, FORGOT_PASSWORD_TEMPLATE, model);
	}

	public void sendActivationCode(UserDTO user, String code) {
		logger.debug(user.getUsername() + " requested a new password");
		Map<String, String> model = new HashMap<String, String>();
		model.put("name", user.getUsername());
		model.put("code", code);
		sendMail(user.getEmail(), ACTIVATION_SUBJECT, ACTIVATION_TEMPLATE, model);
	}

	public void sendFriendRequest(UserDTO from, UserDTO to) {
		logger.debug(from.getUsername() + " send a friend request to " + to.getUsername());
		Map<String, String> model = new HashMap<String, String>();
		model.put("from", from.getUsername());
		model.put("to", to.getUsername());
		sendMail(to.getEmail(), FRIEND_REQUEST_SUBJECT, FRIEND_REQUEST_TEMPLATE, model);
	}

	public void sendFriendAccept(String fromUser, String toUser, Set<String> emails) {
		if (emails != null && emails.size() > 0) {
			logger.debug(toUser + " accepted the friend request of" + toUser);
			Map<String, String> model = new HashMap<String, String>();
			model.put("from", fromUser);
			model.put("to", toUser);
			for (String m : emails) {
				sendMail(m, FRIEND_ACCEPT_SUBJECT, FRIEND_ACCEPT_TEMPLATE, model);
			}
		}
	}

	public void sendXmasCard(String fromUser, String toUser, String toEmail, String url) {
		logger.debug(fromUser + " send " + toEmail + " a xmas card");
		Map<String, String> model = new HashMap<String, String>();
		model.put("from", fromUser);
		model.put("to", toUser);
		model.put("url", url);
		sendMail(toEmail, fromUser + XMAS_WISH_TITLE, XMAS_WISH_TEMPLATE, model);
	}

	public void sendXmasCardReport(String from, String userList, String toEmail, String url) {
		Map<String, String> model = new HashMap<String, String>();
		model.put("from", from);
		model.put("users", userList);
		model.put("url", url);		
		sendMail(toEmail, XMAS_WISH_REPORT_TITLE, XMAS_WISH_REPORT_TEMPLATE, model);
	}

	private void sendMail(String to, String subject, String tmp, Map<String, String> model) {
		try {
			MimeMessage message = mailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(message, true);
			helper.setFrom(DEFAULT_NOREPLY_FROM);
			helper.setTo(to);
			helper.setSubject(subject);
			String body = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, tmp, model);
			helper.setText(body, true);
			SendEmailTask t = new SendEmailTask(mailSender, to, subject, body);
			queue.add(t);
		} catch (Exception e) {
			logger.error("Cannot sending email - ", e);
		}
	}
}

class SendEmailTask implements Callable<Boolean> {
	private String to;
	private String subject;
	private String body;
	private JavaMailSenderImpl mailSender;

	public SendEmailTask(JavaMailSenderImpl mailSender, String tos, String subject, String body) {
		this.mailSender = mailSender;
		this.to = tos;
		this.subject = subject;
		this.body = body;
	}

	public Boolean call() throws Exception {
		try {
			MimeMessage message = mailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(message, true);
			helper.setFrom(MailServiceImpl.DEFAULT_NOREPLY_FROM);
			helper.setTo(to);
			helper.setSubject(subject);
			helper.setText(body, true);
			mailSender.send(message);
		} catch (Exception e) {
			return Boolean.FALSE;
		}
		return Boolean.TRUE;
	}

}
